package com.amkai.aes.webservice.binary.objecthandler.billing;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;

import com.amkai.aes.aescommon.service.binary.job.billing.ChargeProviderJob;
import com.amkai.aes.aescommon.service.result.billing.ChargeProviderResult;
import com.amkai.aes.generatedbeans.billingledger.Charge;
import com.amkai.aes.generatedbeans.billingledger.ChargeDiagnosisAssociation;
import com.amkai.aes.generatedbeans.organization.BusinessGroup;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.pmcase.PmCase;
import com.amkai.aes.generatedbeans.scheduling.AbstractAppointment;
import com.amkai.aes.generatedbeans.scheduling.AppointmentRelation;
import com.amkai.aes.generatedbeans.scheduling.AppointmentStatusInfo;
import com.amkai.aes.generatedbeans.scheduling.ResourceConnection;
import com.amkai.aes.generatedbeans.scheduling.ResourceConnectionProperty;
import com.amkai.aes.generatedbeans.scheduling.SurgeonConnectionProperty;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;

public class ChargeProviderHandler implements JobObjectHandler<ChargeProviderJob, Serializable, ChargeProviderResult>{
	
	@Override
	@SuppressWarnings("unchecked")
	public ChargeProviderResult process(ChargeProviderJob job, Serializable object) throws Exception {
		ChargeProviderResult result = new ChargeProviderResult();
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try{
			switch(job.getKind()){
				case SEARCH :
					//#12696
//					String queryString = "FROM AbstractAppointment AS appointment WHERE appointment.beginTime <= :thru AND appointment.endTime >= :from AND appointment.person.id = :person";
					String queryString = "FROM AbstractAppointment AS appointment LEFT JOIN FETCH appointment.department AS dep LEFT JOIN FETCH dep.parent WHERE appointment.beginTime <= :thru AND appointment.endTime >= :from AND appointment.person.id = :person";
					//#12650
					if (job.getBusinessGroupId() != null) {
						queryString += " AND dep.parent.id = :bg";
					}
					else if(job.getDepartmentId() != null){
						queryString += " AND appointment.department.id = :department"; 
					}
					
					Query query = sm.execute(queryString);
					//#12650
					if (job.getBusinessGroupId() != null) {
						query.setParameter("bg", job.getBusinessGroupId());					
					}
					else if(job.getDepartmentId() != null){
						query.setParameter("department", job.getDepartmentId());					
					}
//					System.out.println("Range: " + job.getFrom().toString() + " - " + job.getThru().toString());
					query.setParameter("from", job.getFrom() != null ? job.getFrom().getTime() : Long.MIN_VALUE);
					query.setParameter("thru", job.getThru() != null ? job.getThru().getTime() : Long.MAX_VALUE);
					query.setParameter("person", job.getPersonId());
					
					List<AbstractAppointment> appointments = new ArrayList<AbstractAppointment>(query.list());						
					for(AbstractAppointment appointmentIterator : appointments){
						fetchAppointment(sm, appointmentIterator);
					}
					
					result.setAppointments(appointments);
					break;
				case DOWNLOAD :
					if(job.getAppointmentId() != null){
						result.setAppointment(fetchAppointment(sm, sm.get(AbstractAppointment.class, job.getAppointmentId())));
					}
					break;
				case REASSIGN_CASE :
					if(job.getAppointmentId() != null && job.getPmCaseId() != null){
						sm.openTransaction();
						try{
							AbstractAppointment appointment = sm.get(AbstractAppointment.class, job.getAppointmentId());
							PmCase pmCase = sm.get(PmCase.class, job.getPmCaseId());
							
							appointment.setPmCase(pmCase);
							
							sm.saveRAD(appointment);							
							sm.commitTransaction();
						}catch(Exception exception){
							exception.printStackTrace();
							sm.rollbackTransaction();
						}
					}
					break;
			}
		}finally{
			sm.closeSession();
		}
		return result;
	}
	
	protected void fetchCharge(SessionManager sm, Charge charge) throws Exception {
		if(charge.getFacility() != null){
			charge.getFacility().getId();
			charge.getFacility().getName();
		}
		if(charge.getProcedure() != null){
			charge.getProcedure().getId();
			charge.getProcedure().getName();
		}
		if(charge.getSupplyResource() != null){
			charge.getSupplyResource().getId();
			charge.getSupplyResource().getName();			
		}
		if(charge.getBatch() != null){
			if(charge.getBatch().getPeriod() != null){
				if(charge.getBatch().getPeriod().getBaseOrganization() != null && charge.getBatch().getPeriod().getBaseOrganization() instanceof Department){
					Department department = sm.get(Department.class, charge.getBatch().getPeriod().getBaseOrganization().getId());
					department.getId();
					department.getName();
					department.getDepartmentType().getKindWrapper().getName();
				}
			}
		}
		if(charge.getFromEntry() != null){
			charge.getFromEntry().getKindWrapper().getId();
			if(charge.getFromEntry().getPerson() != null){
				charge.getFromEntry().getPerson().getDisplayName();
			}
			if(charge.getFromEntry().getInsurancePolicy() != null){
				if(charge.getFromEntry().getInsurancePolicy().getInsuranceClaimOffice() != null){
					if(charge.getFromEntry().getInsurancePolicy().getInsuranceClaimOffice().getInsuranceCarrier() != null){
						charge.getFromEntry().getInsurancePolicy().getInsuranceClaimOffice().getInsuranceCarrier().getName();
					}
				}
			}
		}
		if(charge.getChargeDiagnosisAssociations() != null){
			for(ChargeDiagnosisAssociation diagnosis : charge.getChargeDiagnosisAssociations()){
				diagnosis.getDiagnosis().getId();
				diagnosis.getDiagnosis().getShortName();
				// KKORNEL: AES-13961
				if (diagnosis.getPresentOnAdmission() != null) {
					diagnosis.getPresentOnAdmission().getName();
				}
			}
		}
	}
	
	protected AbstractAppointment fetchAppointment(SessionManager sm, AbstractAppointment appointment) throws Exception {
		appointment.getAppointmentType().getId();
		appointment.getAppointmentType().getName();
		
		if(appointment.getPmCase() != null){
			appointment.getPmCase().getId();
			appointment.getPmCase().getName();

			if(appointment.getPmCase().getPrimaryCase() != null){
				appointment.getPmCase().getPrimaryCase().getId();
				appointment.getPmCase().getPrimaryCase().getName();				
			}
		}
		if(appointment.getDepartment() != null && appointment.getDepartment().getDepartmentType() != null){
			appointment.getDepartment().getId();
			appointment.getDepartment().getName();
			appointment.getDepartment().getDepartmentType().getId();
			appointment.getDepartment().getDepartmentType().getKindWrapper().getName();
			//#12696
			appointment.getDepartment().getParent();
			if ((appointment.getDepartment().getParent() != null) && (appointment.getDepartment().getParent() instanceof BusinessGroup)) {
				BusinessGroup businessGroup = (BusinessGroup)appointment.getDepartment().getParent();
				businessGroup.getKind();
				businessGroup.getLevel();
				businessGroup.getName();
				businessGroup.getId();
				
			}
		}
		if(appointment.getFacility() != null){
			appointment.getFacility().getId();
			appointment.getFacility().getName();
		}
		
		for(ResourceConnection resourceConnection : appointment.getResourceConnections()){
			resourceConnection.getId();
			resourceConnection.getReservation().getId();
			resourceConnection.getReservation().getSchedulingResource().getId();
			resourceConnection.getReservation().getSchedulingResource().getTitle();
			
			Set<ResourceConnectionProperty> resourceConnectionProperties = new HashSet<ResourceConnectionProperty>();
			for(ResourceConnectionProperty resourceConnectionProperty : resourceConnection.getResourceConnectionProperty()){
				switch(resourceConnectionProperty.getPropertyKind()){
					case RCP_SCP:
						SurgeonConnectionProperty surgeonConnectionProperty = sm.get(SurgeonConnectionProperty.class, resourceConnectionProperty.getId());
						resourceConnectionProperties.add(surgeonConnectionProperty);
						break;
				}
			}
			resourceConnection.setResourceConnectionProperty(resourceConnectionProperties);
		}
		
		for(PmCase pmCase : appointment.getPmCaseINVmainAppointment()){
			pmCase.getName();
		}
		
		for(AppointmentStatusInfo info : appointment.getAppointmentStatusInfoes()){
			info.getStatusKindWrapper().getName();
		}
		
		for(AppointmentRelation related : appointment.getAppointmentRelations()){
			related.getTargetAppointment().getId();
			related.getOwnerAppointment().getId();
		}
		
		for(Charge charge : appointment.getCharges()){
			fetchCharge(sm, charge);
		}
		
		return appointment;
	}
}
